package club.kynb.mall.application.flow.order;

import club.kynb.mall.application.context.MallUserContext;
import club.kynb.mall.application.context.OrderSubmitContext;
import club.kynb.mall.application.model.model.command.SubmitOrderCommand;
import club.kynb.mall.application.model.model.dto.PreviewOrderDTO;
import club.kynb.mall.application.model.model.dto.PreviewOrderDetailDTO;
import club.kynb.mall.application.model.model.dto.PreviewOrderSkuDTO;
import club.kynb.mall.application.model.model.dto.PreviewOrderSpuDTO;
import club.kynb.mall.order.api.IOrderService;
import club.kynb.mall.order.constant.OrderPayStatusEnum;
import club.kynb.mall.order.constant.OrderStatusEnum;
import club.kynb.mall.order.model.dto.OrderDTO;
import club.kynb.mall.order.model.dto.OrderDetailDTO;
import club.kynb.mall.product.api.ICouponService;
import club.kynb.mall.product.dto.ProductSkuDTO;
import club.kynb.mall.product.dto.ProductSpuDetailDTO;
import club.kynb.mall.user.model.dto.ShippingAddressDTO;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.pizza.common.web.exception.Errors;
import org.pizza.id.api.IdGenerator;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author kynb_club@163.com
 * @since 2021/7/7 1:56 下午
 */
@Slf4j
@Component
@AllArgsConstructor
public class DoSubmitOrderFilter extends AbstractSubmitOrderFlowFilter {
    private final IdGenerator idGenerator;
    private final IOrderService iOrderService;
    private final ICouponService iCouponService;
    private final TransactionTemplate transactionTemplate;

    @Override
    protected void doService(OrderSubmitContext orderSubmitContext) {
        //填充订单
        this.fillOrder(orderSubmitContext);
        //填充订单详情
        this.fillOrderDetailList(orderSubmitContext);
        log.info("订单编号：{} ,填充订单与订单详情完成 -> \n订单信息：{} \n订单详情信息：{}", orderSubmitContext.getPreviewOrder().getInnerOrderNo(), JSONUtil.toJsonStr(orderSubmitContext.getOrderDTO()), JSONUtil.toJsonStr(orderSubmitContext.getOrderDetailList()));
        transactionTemplate.executeWithoutResult(transactionStatus -> {
            //持久化订单
            iOrderService.createOrder(orderSubmitContext.getOrderDTO(), orderSubmitContext.getOrderDetailList());
            if (Objects.nonNull(orderSubmitContext.getUsedCoupon())) {
                //优惠券扣减
                iCouponService.useCoupon(orderSubmitContext.getUsedCoupon().getId());
            }
            //TODO 库存锁定

        });
    }



    private void fillOrderDetailList(OrderSubmitContext orderSubmitContext) {
        final MallUserContext mallUserContext = MallUserContext.get(true);
        final SubmitOrderCommand command = orderSubmitContext.getCommand();
        final PreviewOrderDTO previewOrder = orderSubmitContext.getPreviewOrder();
        final List<PreviewOrderDetailDTO> previewOrderOrderDetailList = previewOrder.getOrderDetailList();
        final List<ProductSpuDetailDTO> innerSpuList = orderSubmitContext.getInnerSpuList();
        final Map<String, ProductSpuDetailDTO> spuMap = innerSpuList.stream().collect(Collectors.toMap(ProductSpuDetailDTO::getId, productSpuDTO -> productSpuDTO, (p1, p2) -> p2));
        final Map<String, ProductSkuDTO> skuMap = innerSpuList.stream().flatMap(productSpuDTO -> productSpuDTO.getSkuList().stream())
                .collect(Collectors.toMap(ProductSkuDTO::getId, productSkuDTO -> productSkuDTO, (p1, p2) -> p2));
        //预览订单详情 -> 提交订单详情
        final List<OrderDetailDTO> orderDetailList = previewOrderOrderDetailList.stream()
                .map(previewOrderDetailDTO -> {
                    final PreviewOrderSpuDTO previewOrderSpuDTO = previewOrderDetailDTO.getPreviewOrderSpuDTO();
                    final PreviewOrderSkuDTO previewOrderSkuDTO = previewOrderSpuDTO.getPreviewOrderSkuDTO();
                    //找到内部SPU
                    final ProductSpuDetailDTO productSpuDTO = spuMap.get(previewOrderSpuDTO.getId());
                    //找到内部SKU
                    final ProductSkuDTO productSkuDTO = skuMap.get(previewOrderSkuDTO.getId());
                    if (productSkuDTO == null) {
                        log.error("系统异常，预览订单sku没有找到对应信息:{}", JSONUtil.toJsonStr(previewOrderSkuDTO));
                        throw Errors.SYSTEM.exception("系统异常，预览订单sku没有找到对应信息");
                    }
                    List<ProductSkuDTO> skuList = new ArrayList<>();
                    skuList.add(productSkuDTO);
                    productSpuDTO.setSkuList(skuList);

                    //<---填充属性--->
                    final long id = idGenerator.nextId(OrderDetailDTO.class);
                    final OrderDetailDTO orderDetailDTO = new OrderDetailDTO();
                    orderDetailDTO.setId(id);
                    orderDetailDTO.setUserId(mallUserContext.getUserDTO().getId());
                    orderDetailDTO.setInnerOrderNo(command.getInnerOrderNo());
                    orderDetailDTO.setSpuId(Long.valueOf(previewOrderSpuDTO.getId()));
                    orderDetailDTO.setSkuId(Long.valueOf(previewOrderSkuDTO.getId()));
                    orderDetailDTO.setSkuNum(previewOrderSkuDTO.getSkuNum());
                    orderDetailDTO.setTotalAmount(NumberUtil.mul(productSkuDTO.getSkuPrice(), new BigDecimal(previewOrderSkuDTO.getSkuNum())));
                    //TODO 计算优惠均摊
                    orderDetailDTO.setShareAmount(new BigDecimal("0"));
                    orderDetailDTO.setSkuSnapshoot(JSONUtil.toJsonStr(productSpuDTO));
                    return orderDetailDTO;
                }).collect(Collectors.toList());
        orderSubmitContext.setOrderDetailList(orderDetailList);
    }

    private void fillOrder(OrderSubmitContext orderSubmitContext) {
        final SubmitOrderCommand command = orderSubmitContext.getCommand();
        final String innerOrderNo = command.getInnerOrderNo();
        final MallUserContext mallUserContext = MallUserContext.get(true);
        final long id = idGenerator.nextId(OrderDTO.class);
        final ShippingAddressDTO shippingAddress = orderSubmitContext.getShippingAddress();
        //属性填充
        final OrderDTO orderDTO = orderSubmitContext.getOrderDTO();
        orderDTO.setId(id);
        orderDTO.setUserId(mallUserContext.getUserDTO().getId());
        orderDTO.setOuterOrderNo(microSecondString());
        orderDTO.setInnerOrderNo(innerOrderNo);
        orderDTO.setOrderStatus(OrderStatusEnum.UNPAID.code());
//        orderDTO.setTotalAmount(new BigDecimal("0"));
//        orderDTO.setPayableAmount(new BigDecimal("0"));
//        orderDTO.setPayAmount(new BigDecimal("0"));
//        orderDTO.setFreightAmount(new BigDecimal("0"));
//        orderDTO.setDiscountAmount(new BigDecimal("0"));
//        orderDTO.setCouponAmount(new BigDecimal("0"));
//        orderDTO.setTotalItemNum(0);
        orderDTO.setUserCouponId(command.getUserCouponId());
        orderDTO.setPlaceTime(new Date());
        orderDTO.setAutoDeliveryTime(DateUtil.offsetDay(new Date(), 7));
        orderDTO.setEndTime(null);
        orderDTO.setCancelEndTime(DateUtil.offsetMinute(new Date(), 30));
        orderDTO.setPayChannel(command.getPayChannel());
        orderDTO.setPayCreateTime(null);
        orderDTO.setPayStatus(OrderPayStatusEnum.NO_PAY.getStatus());
        orderDTO.setPayFinishTime(null);
        orderDTO.setDepositPayTime(null);
        orderDTO.setCancelTime(null);
        orderDTO.setCancelType("");
        orderDTO.setCancelDesc("");
        orderDTO.setDeliveryType("");
        orderDTO.setDeliveryName(shippingAddress.getContact());
        orderDTO.setDeliveryMobile(shippingAddress.getPhone());
        orderDTO.setDeliveryAddress(StrUtil.nullToEmpty(shippingAddress.getAddress())+StrUtil.nullToEmpty(shippingAddress.getHouseNo()));
        orderDTO.setConfirmDeliveryTime(null);
        orderDTO.setActualArriveTime(null);
        orderDTO.setPayNo("");
        orderDTO.setUserRemark(command.getUserRemark());
        orderDTO.setExtension("");
    }

    /**
     *
     */
    private static String formatString(Date date, String format) {
        if (date == null) {
            date = new Date();
        }
        if (format == null) {
            format = "yyyy-MM-dd HH:mm:ss";
        }
        SimpleDateFormat df = new SimpleDateFormat(format);
        return df.format(date);
    }

    /**
     * 临时使用
     */
    private static String microSecondString() {
        String string = formatString(new Date(), "yyyyMMddHHmmssSSS");
        Long nanoTime = System.nanoTime() % 1000;
        return String.format("%s%03d", string, nanoTime);
    }
}
